<?php
/*
 * CK框架 的cache所有对象
 * @category   CkFrameWork
 * @package  CkFrameWork
 * @subpackage lib
 * @author    wujibing<283109896@qq.com>
 * @version   2.0
 */
/**
 * 缓存接口
 * @author wujibing<283109896@qq.com>
 * @version   1.0
 * @category   CkFrameWork
 * @package  CkFrameWork
 * @subpackage lib
 */
interface I_cache
{

	/**
	 * 设置缓存
	 * @param string $id 缓存名
	 * @param mixed $value 缓存值
	 * @param int $expire 缓存周期  0 为永久
	 * @return mixed
	 */
	public function set ($id, $value, $expire = 0);

	/**
	 * 获取缓存
	 * @param string $id 读取的缓存ID
	 * @return mixed
	 */
	public function get ($id);

	/**
	 * 删除缓存
	 * @param string $id 删除的缓存ID
	 * @return mixed
	 */
	public function del ($id);

	/**
	 * 清理缓存
	 */
	public function clear ();
}

/**
 * 文件缓存的父类
 * @author wujibing<283109896@qq.com>
 * @version   1.0
 * @category   CkFrameWork
 * @package  CkFrameWork
 * @subpackage lib
 */
class fileCacheBase
{
    /**
     * 缓存的文件夹
     * @var string
     */
    protected $_cacheDir;
    /**
     * 缓存的文件后缀
     * @var string
     */
    protected $_cacheExt;
    public function __construct($configObject)
    {
        if (!$configObject->CACHE_DIR)
        {
            throw new base_Exception(lang::getLang('__CHANGE_CACHE_DIR__'));
        }
        $this->_cacheDir = CK_APPLICATION_DATA_DIR .'/'. 'cache/' . $configObject->CACHE_DIR.'/';
        $this->_cacheExt = $configObject->CACHE_EXT;
    }
    
    public function del ($id)
	{
		@unlink($this->getFile($id));
	}

	public function clear ()
	{
		dir::delDir($this->_cacheDir);
	}
    protected function getFile($id)
    {
        $md5 = md5($id);
        $md5 = $this->_cacheDir . '/' . $md5[0] . '/' . $md5 .'.'.$this->_cacheExt;
        dir::mkDir(dirname($md5));
        return $md5;
    }
}
/**
 * memcached缓存
 * @author wujibing<283109896@qq.com>
 * @version   1.0
 * @category   CkFrameWork
 * @package  CkFrameWork
 * @subpackage lib
 */
class CKMEMCACHE implements I_cache
{
	/**
	 * memcache对象
	 * @var Memcached
	 */
	private $_memcache;
    /**
     * 初始化
     * @param unknown_type $configObject
     */
	public function __construct ($configObject)
	{
		$this->_memcache = new Memcached(); //Memcached
		//是否多台memcache缓存服务器
		$count = count($configObject);
		if($count == 0)
		{
		    throw new base_Exception(lang::getLang('__HAS_NONE_MEMCACHED_SERVER__'));
		} else if($count == 1)
		{
		    $this->_memcache->addServer($configObject[0]['HOST'], $configObject[0]['PORT'], $configObject[0]['WEIGHT']);
		} else 
		{
		    $tmpArray = array();
		    foreach ($configObject as $memCacheValue)
		    {
		        $tmpArray[] = array($memCacheValue['HOST'], $memCacheValue['PORT'], $memCacheValue['WEIGHT']);
		    }
		    $this->_memcache->addServers($tmpArray);
		}
		
	}

	public function get ($id)
	{
		return $this->_memcache->get($id);
	}

	public function set ($id, $value, $expire = 0)
	{
		return $this->_memcache->set($id, $value, $expire);
	}

	public function clear ()
	{
		return $this->_memcache->flush();
	}

	public function del ($id)
	{
		return $this->_memcache->delete($id);
	}
}

/**
 * CK框架 文件缓存
 * @author wujibing<283109896@qq.com>
 * @version   1.0
 * @category   CkFrameWork
 * @package  CkFrameWork
 * @subpackage lib
 */
class CKFILECACHE extends fileCacheBase implements I_cache
{
	/**
	 * (non-PHPdoc)
	 * @see I_cache::set()
	 */
	public function set ($id, $value, $expire = 0)
	{
		$newArr = array('data' => $value, 'cacheTime' => $expire);
		file_put_contents($this->getFile($id), serialize($newArr), LOCK_EX);
	}
	/**
	 * (non-PHPdoc)
	 * @see I_cache::get()
	 */
	public function get ($id)
	{
		$file = $this->getFile($id);
		if (! file_exists($file))
		{
			return false;
		}
		$fileContent = file_get_contents($file);
		$arr = unserialize($fileContent);
		if (SYSTIME > $arr['cacheTime'] && $arr['cacheTime'] != 0)
		{
			return false;
		}
		return $arr['data'];
	}
}

/**
 * CK框架 PHP文件缓存
 * @author wujibing<283109896@qq.com>
 * @version   1.0
 * @category   CkFrameWork
 * @package  CkFrameWork
 * @subpackage lib
 */
class CKPHPCACHE extends fileCacheBase implements I_cache
{
	public function set ($id, $value, $expire = 0)
	{
		file_put_contents($this->getFile($id), 
		'<?php return array(\'cacheTime\' => ' . $expire . ',\'data\' => array(' . var_export($value, true) . '));', 
		LOCK_EX);
	}

	public function get ($id)
	{
		$cFile = $this->getFile($id);
		if (file_exists($cFile))
		{
			$data = include $cFile;
			if ($data['cacheTime'] == 0 || SYSTIME < $data['cacheTime'])
			{
				return $data['data'];
			} else
			{
				return false;
			}
		}
		return false;
	}
}

/**
 * CK框架 cache代理类
 * @author wujibing<283109896@qq.com>
 * @version   1.0
 * @category   CkFrameWork
 * @package  CkFrameWork
 * @subpackage lib
 */
class cache
{

	/**
	 * 现在的CACHE实例数组
	 * @var array
	 */
	private static $caches = array();

	/**
	 * 当前的CACHE实例
	 * @var I_cache
	 */
	private static $nowCache;

	/**
	 * 当前CACHE实例的名称
	 * @var string
	 */
	private static $nowCacheName;

	/**
	 * 缓存数据数组
	 * @var array
	 */
	private static $datas;

	/**
	 * 初始化缓存
	 * @param string $cacheName 缓存实例可以从 cacheType类中读取 例如 cacheType::PHP
	 * @throws base_base_Exception
	 */
	public static function init ($cacheName) //实例一个Cache
	{
		if (! isset(self::$caches[$cacheName]))
		{
			$cacheName2 = $cacheName . 'CACHE';
			if (! in_array($cacheName, array('FILE', 'MEM', 'PHP')))
			{
				throw new base_Exception(lang::getLang('__ERROR_CACHE_OBJECT_NAME__'), __LINE__);
			}
			$config = config::$configObject->CACHE->$cacheName2;
			if (!$config)
			{
				throw new base_Exception(lang::getLang('__CACHE_CONFIG_NOT_FOUND__',array($cacheName2)), __LINE__);
			}
			$cacheName2 = 'CK'.$cacheName2;
			self::$caches[$cacheName] = new $cacheName2($config);
		}
		self::$nowCache = self::$caches[$cacheName];
		self::$nowCacheName = $cacheName;
	}

	/**
	 * 设置缓存
	 * @param string $id 缓存名
	 * @param mixed $value 缓存值
	 * @param int $expire 缓存周期 0为永久
	 */
	public static function set ($id, $value, $expire = 0)
	{
		self::checkObj();
		if ($expire)
		{
			$expire = SYSTIME + $expire;
		}
		self::$nowCache->set($id, $value, $expire);
	}

	/**
	 * 读取缓存
	 * @param string $id
	 * @param boolean $isNotNew 如果有缓存数据 则不重新读取缓存
	 * @param array $callBack
	 * 如果读取失败 则回调调用的函数  参见call_user_func_array
	 * 函数必须返回包含 ['data','time']的数组信息。time为缓存时间 data为缓存内容
	 * 缓存将重新根据函数返回的结果设置缓存
	 * @return mixed
	 */
	public static function get ($id, $isNotNew = true, $callBack = NULL)
	{
		self::checkObj();
		//判断获取过没
		$md5Hash = md5(self::$nowCacheName . $id);
		if (isset(self::$datas[$md5Hash]) && $isNotNew)
		{
			return self::$datas[$md5Hash];
		}
		$return = self::$nowCache->get($id);
		if ($return)
		{
			self::$datas[$md5Hash] = $return;
		} elseif ($callBack)
		{
			if (! isset($callBack[2]))
			{
				$callBack[2] = array();
			} elseif (! is_array($callBack[2]))
			{
				$callBack[2] = array($callBack[2]);
			}
			$return = call_user_func_array(array($callBack[0], $callBack[1]), $callBack[2]);
			if (! $return || !$return['data'])
			{
				return false;
			}
			cache::set($id, $return['data'], $return['time']);
			return $return['data'];
		}
		return $return;
	}

	/**
	 * 删除缓存
	 * @param string $id 删除的缓存名
	 * @return mixed
	 */
	public static function del ($id)
	{
		self::checkObj();
		return self::$nowCache->del($id);
	}

	/**
	 * 清空缓存
	 */
	public static function clear ()
	{
		self::checkObj();
		return self::$nowCache->clear;
	}

	/**
	 * 检查是否实例化了缓存
	 * @throws base_base_Exception
	 */
	private static function checkObj ()
	{
		if (! self::$nowCacheName)
		{
			throw new base_Exception(lang::getLang('__NOT_CACHE_OBJECT_INIT__'));
		}
	}
}

/**
 * CK框架 缓存类型
 * @author wujibing<283109896@qq.com>
 * @version   3.0
 * @category   CkFrameWork
 * @package  CkFrameWork
 * @subpackage lib
 */
final class cacheType
{

	/**
	 * file类型缓存
	 * @var string
	 */
	const FILE = 'FILE';

	/**
	 * memcache类型缓存
	 * @var string
	 */
	const MEMCACHES = 'MEM';

	/**
	 * php类型缓存
	 * @var string
	 */
	const PHP = 'PHP';
}
/**
 * CK框架 获取当前页面的缓存名等
 * @author wujibing<283109896@qq.com>
 * @version   3.0
 * @category   CkFrameWork
 * @package  CkFrameWork
 * @subpackage lib
 */
class pageCache
{
    /**
     * 获取当前页面的缓存ID
     * @return string
     */
    public static function getPageId()
    {
        return md5($_SERVER['REQUEST_URI']).'ckFrameWorkPageCache';
    }
}